package ohm.quickdice.control;

import ohm.quickdice.R;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;

public class GraphicManager {
	
	public static final int INDEX_DICE_ICON_MALUS = -2;
	public static final int INDEX_DICE_ICON_BONUS = -1;
	public static final int INDEX_DICE_ICON_DEFAULT = 0;

	private static Paint getShapePaint = null;
	private static Canvas getShapeCanvas = null;
	private static Canvas drawableToBitmapCanvas = null;
	private static int[] diceIconIDs;
	private static int[] diceColors;

	Context context;
	Resources res;
	float density;
	
	/**
	 * Initialize a graphic helper with specified {@link Resources}.
	 * @param res {@link Resources} to use.
	 */
	public GraphicManager(Context context) {
		this.context = context;
		this.res = context.getResources();
		this.density = res.getDisplayMetrics().density;
		initIcons();
	}
	
	private void initIcons() {
		TypedArray myDiceIcons;
		TypedArray myDiceColors;

		if (diceIconIDs == null) {
			myDiceIcons = res.obtainTypedArray(R.array.diceIcons);
			diceIconIDs = new int[myDiceIcons.length()];
			for (int i = 0; i < diceIconIDs.length; i++) {
				diceIconIDs[i] = myDiceIcons.getResourceId(i, R.drawable.ic_dxx_gray);
			}
			myDiceIcons.recycle();
		}

		if (diceColors == null) {
			myDiceColors = res.obtainTypedArray(R.array.diceColors);
			diceColors = new int[myDiceColors.length()];
			for (int i = 0; i < diceColors.length; i++) {
				diceColors[i] = myDiceColors.getColor(i, 0);
			}
			myDiceColors.recycle();
		}
	}
	
	/**
	 * Read the number of available dice icons.
	 * @return Number of available dice icons.
	 */
	public int getDiceIconCount() {
		return diceIconIDs.length;
	}

	/**
	 * Get the {@link Drawable} of the icon at the given index.
	 * @param index Index of the icon.
	 * @return {@link Drawable} of an icon.
	 */
	public Drawable getDiceIcon(int index) {
		if (index <= 0 || index >= diceIconIDs.length) {
			if (index == INDEX_DICE_ICON_BONUS) {
				return res.getDrawable(R.drawable.ic_bonus);
			} else if (index == INDEX_DICE_ICON_MALUS) {
				return res.getDrawable(R.drawable.ic_malus);
			} else {
				return res.getDrawable(R.drawable.ic_dxx_gray);
			}
		} else {
			return res.getDrawable(diceIconIDs[index]);
		}
	}

	/**
	 * Get the resized {@link Drawable} of the icon at the given index.
	 * @param index Index of the icon.
	 * @param width Desired width in {@code dp}.
	 * @param height Desired height in {@code dp}.
	 * @return Resized {@link Drawable} of an icon.
	 */
	public Drawable getResizedDiceIcon(int index, int width, int height) {
		return resizeDrawable(getDiceIcon(index), width, height);
	}

	/**
	 * Get the resized {@link Drawable} of the icon at the given index.
	 * @param iconIndex Index of the icon.
	 * @param colorIndex Index of the color.
	 * @return Resized {@link Drawable} of an icon.
	 */
	public Drawable getDiceIconShape(int iconIndex, int colorIndex) {
		Drawable icon = getDiceIcon(iconIndex);
		int color = getDiceColor(colorIndex);
		return getShape(icon, color);
	}

	/**
	 * Read the number of available dice colors.
	 * @return Number of available dice colors.
	 */
	public int getDiceColorCount() {
		return diceColors.length;
	}
	
	/**
	 * Get the color for the icon at the given index.
	 * @param index Index of the color.
	 * @return Color of an icon.
	 */
	public int getDiceColor(int index) {
		if (index <= 0 || index >= diceColors.length) {
			return diceColors[0];
		} else {
			return diceColors[index];
		}
	}

	/**
	 * Resize a {@link Drawable} to the given size.<br />
	 * Metrics and density are given by the {@link Resources} bount to this instance.
	 * @param id The desired resource identifier, as generated by the aapt tool. This integer encodes the package, type, and resource entry. The value 0 is an invalid identifier.
	 * @param width Desired width in {@code dp}.
	 * @param height Desired height in {@code dp}.
	 * @return A scaled {@link Drawable}.
	 */
	public Drawable resizeDrawable(int id, int width, int height) {
		return resizeDrawable(res.getDrawable(id), width, height);
	}

	/**
	 * Resize a {@link Drawable} to the given size.<br />
	 * Metrics and density are given by the {@link Resources} bount to this instance.
	 * @param source {@link Drawable} to resize.
	 * @param width Desired width in {@code dp}.
	 * @param height Desired height in {@code dp}.
	 * @return A scaled {@link Drawable}.
	 */
	private Drawable resizeDrawable(Drawable source, int width, int height) {
		return new BitmapDrawable(
				res,
				resizeBitmap(drawableToBitmap(source), width, height));
	}

	/**
	 * Resize a {@link Bitmap} to the given size.<br />
	 * Metrics and density are given by the {@link Resources} bount to this instance.
	 * @param source {@link Bitmap} to resize.
	 * @param width Desired width in {@code dp}.
	 * @param height Desired height in {@code dp}.
	 * @return A scaled {@link Bitmap}.
	 */
	private Bitmap resizeBitmap(Bitmap source, int width, int height) {
		return Bitmap.createScaledBitmap(
				source,
				(int)(width * density),
				(int)(height * density),
				true);
	}

	/**
	 * Get a shape of color {@code color} using the alpha channel of {@code source}.
	 * @param source Source {@link Drawable} containing the shape alpha channel.
	 * @param color Color of the shape.
	 * @return A {@link Bitmap} containing the shape of the given color.
	 */
	private Drawable getShape(Drawable source, int color) {
		return new BitmapDrawable(res, getShape(drawableToBitmap(source), color));
	}
	
	/**
	 * Get a shape of color {@code color} using the alpha channel of {@code source}.
	 * @param source Source image containing the shape alpha channel.
	 * @param color Color of the shape.
	 * @return A {@link Bitmap} containing the shape of the given color.
	 */
	private Bitmap getShape(Bitmap source, int color) {
		Bitmap retVal;
		
		retVal = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
		retVal.eraseColor(color);
		
		if (getShapePaint == null) {
			getShapePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
			getShapePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
		}
		
		if (getShapeCanvas == null) {
			getShapeCanvas = new Canvas();
		}
		//Using a shared Canvas reduce memory footprint but may lead to race condition!
		getShapeCanvas.setBitmap(retVal);
		getShapeCanvas.drawBitmap(source, 0, 0, getShapePaint);
		
		return retVal;
	}

//	/**
//	 * Resize a {@link Drawable} to the given size using the specified metrics.
//	 * @param source {@link Drawable} to resize.
//	 * @param width Desired width.
//	 * @param height Desired height.
//	 * @param metrics Display metrics.
//	 * @return A scaled {@link Drawable}.
//	 */
//	public static Drawable resizeDrawable(Drawable source, int width, int height, DisplayMetrics metrics) {
//		return new BitmapDrawable(
//				resizeBitmap(drawableToBitmap(source), width, height, metrics));
//	}
	
//	/**
//	 * Resize a {@link Drawable} to the given size using the specified metrics.
//	 * @param source {@link Drawable} to resize.
//	 * @param width Desired width.
//	 * @param height Desired height.
//	 * @param metrics Display metrics.
//	 * @return A scaled {@link Drawable}.
//	 */
//	public static Drawable resizeDrawable(Drawable source, int width, int height, Resources res) {
//		return new BitmapDrawable(res, 
//				resizeBitmap(drawableToBitmap(source), width, height, metrics));
//		return new BitmapDrawable(res, 
//				resizeBitmap(drawableToBitmap(source), width, height, metrics));
//	}
	
//	/**
//	 * Resize a {@link Bitmap} to the given size using the specified metrics.
//	 * @param source {@link Bitmap} to resize.
//	 * @param width Desired width.
//	 * @param height Desired height.
//	 * @param metrics Display metrics.
//	 * @return A scaled {@link Bitmap}.
//	 */
//	public static Bitmap resizeBitmap(Bitmap source, int width, int height, DisplayMetrics metrics) {
//		return Bitmap.createScaledBitmap(
//				source,
//				(int)(width * metrics.density),
//				(int)(height * metrics.density),
//				true);
//	}
	
	/**
	 * Return the {@link Bitmap} representing the {@link Drawable}.
	 * @param drawable Object to convert to {@link Bitmap}.
	 * @return {@link Bitmap} representing the {@link Drawable}.
	 */
	protected static Bitmap drawableToBitmap(Drawable drawable) {
		Bitmap retVal;
		if (drawable instanceof BitmapDrawable) {
			//Easy
			retVal = ((BitmapDrawable)drawable).getBitmap();
		} else {
			retVal = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
			if (drawableToBitmapCanvas == null) {
				drawableToBitmapCanvas = new Canvas();
			}
			drawableToBitmapCanvas.setBitmap(retVal);
			drawable.draw(drawableToBitmapCanvas); 
		}
		return retVal;
	}
	
//	if (index == 5) {
//	//d12 (bianco)
//	//faccio dei test
//	Drawable retVal = diceIcons.getDrawable(index);
//	Bitmap bmp = ((BitmapDrawable)retVal).getBitmap();
//	Paint p = new Paint(Color.RED);
//	//ColorFilter filter = new LightingColorFilter(Color.RED, 1);
//	ColorFilter filter = new PorterDuffColorFilter(Color.RED, Mode.MULTIPLY);
//	p.setColorFilter(filter);
//	
//	Canvas cnv = new Canvas();
//	
//	Bitmap asd = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888);
//	cnv.setBitmap(asd);
//	cnv.drawBitmap(bmp, 0, 0, p);
//	
//	retVal = new BitmapDrawable(asd);
//
//	return retVal;
//} else if (index == 2 || index == 6) {
//	//d6 (nero)
//	//faccio dei test
//	Drawable retVal = diceIcons.getDrawable(index);
//	Bitmap bmp = ((BitmapDrawable)retVal).getBitmap();
//	Paint p = new Paint(Color.RED);
//	//ColorFilter filter = new LightingColorFilter(Color.RED, 1);
//	//Mode.SCREEN - no
//	//Mode.DARKEN - no
//	//Mode.LIGHTEN - no
//	//Mode.MULTIPLY - no
//	//Mode.SRC_OVER - no
//	//SRC_ATOP - no
//	//SRC_IN - no
//	//SRC_OUT - no
//	//SRC_OVER - no
//	//DST_ATOP - no
//	//XOR - no
//	p.setColor(Color.GRAY);
//	p.setColorFilter(new PorterDuffColorFilter(Color.RED, Mode.SCREEN));
//	p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
//	//p.set
//	
//	Canvas cnv = new Canvas();
//	
//	//Bitmap asd = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888);
//	//Bitmap asd = Graphic.getShape(bmp, Color.WHITE);
//	//Bitmap asd = bmp.extractAlpha().copy(Bitmap.Config.ARGB_8888, true);
//	Bitmap asd = bmp.copy(Bitmap.Config.ARGB_8888, true);
//	cnv.setBitmap(asd);
//	//cnv.drawBitmap(Graphic.getShape(bmp, Color.WHITE), 0, 0, null);
//	cnv.drawBitmap(bmp, 0, 0, p);
//	
//	retVal = new BitmapDrawable(asd);
//
//	return retVal;
//} else {

}
